# -*- python -*-
# ex: set syntax=python:

# Copyright (c) 2012 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.

# READ THIS:
# See http://dev.chromium.org/developers/testing/chromium-build-infrastructure

import os

# These modules come from scripts, which must be in the PYTHONPATH.
from master import master_utils
from master import slaves_list
from master.builders_pools import BuildersPools
from master.factory import annotator_factory
from master.factory import nacl_factory
from master.factory import nacl_ports_factory
from master.try_job_http import TryJobHTTP
from master.try_job_svn import TryJobSubversion
from master.try_job_rietveld import TryJobRietveld

from buildbot.scheduler import Triggerable

import config
import master_site_config

ActiveMaster = master_site_config.NativeClientTryServer

nacl_source_url = (
    'https://chromium.googlesource.com/native_client/src/native_client')

MAIL_NOTIFIER = True
UPDATE_CODEREVIEW = ActiveMaster.is_production_host
LISTEN_TO_RIETVELD = ActiveMaster.is_production_host

# This is the dictionary that the buildmaster pays attention to. We also use
# a shorter alias to save typing.
c = BuildmasterConfig = {}

config.DatabaseSetup(c, require_dbconfig=ActiveMaster.is_production_host)

####### CHANGESOURCES

c['change_source'] = [ ]

# Avoid merging requests.
c['mergeRequests'] = lambda *_: False


####### BUILDERS

c['builders'] = []

# FACTORIES

m_win32 = {}
m_win64 = {}
m_win8 = {}
m_mac = {}
m_linux = {}
m_arm = {}
m_android = {}

m_win32['nacl'] = nacl_factory.NativeClientFactory(
    build_dir='native_client',
    alternate_url=nacl_source_url,
    target_platform='win32').NativeClientFactory
m_win64['nacl'] = nacl_factory.NativeClientFactory(
    build_dir='native_client',
    alternate_url=nacl_source_url,
    # Use win32 for win64 as various bbot parts assume this.
    target_platform='win32').NativeClientFactory
m_win8['nacl'] = nacl_factory.NativeClientFactory(
    build_dir='native_client',
    alternate_url=nacl_source_url,
    # Use win32 for win8 as various bbot parts assume this.
    target_platform='win32').NativeClientFactory
m_linux['nacl'] = nacl_factory.NativeClientFactory(
    build_dir='native_client',
    alternate_url=nacl_source_url,
    target_platform='linux2', target_os='android').NativeClientFactory
m_mac['nacl'] = nacl_factory.NativeClientFactory(
    build_dir='native_client',
    alternate_url=nacl_source_url,
    target_platform='darwin').NativeClientFactory
m_arm['nacl'] = nacl_factory.NativeClientFactory(
    build_dir='native_client',
    alternate_url=nacl_source_url,
    target_platform='arm').NativeClientFactory

for platform in [m_win32, m_win64, m_win8, m_mac, m_linux, m_arm]:
  platform['nacl-toolchain'] = platform['nacl']

git_url = 'https://chromium.googlesource.com/external/naclports.git'
m_linux['naclports'] = nacl_ports_factory.NativeClientPortsFactory(
    name='src',
    build_dir='naclports',
    alternate_url=git_url,
    target_platform='linux2').NativeClientPortsFactory
m_mac['naclports'] = nacl_ports_factory.NativeClientPortsFactory(
    name='src',
    build_dir='naclports',
    alternate_url=git_url,
    target_platform='darwin').NativeClientPortsFactory

def CreateBot(platform, password=config.Master.GetBotPassword(),
              builder_name=None, target=None, project=None,
              tests=None, options=None, mode=None, timeout=1200,
              slave_names=None, factory_properties=None, slave_type='Trybot',
              slavebuilddir=None):
  """Generates and register a builder along with its slave(s).

  Implicitly register slave_name or slave_names if they weren't registered yet.
  If none of slave_name or slave_names is supplied, a slave name will be
  constructed from the builder name.
  """
  if platform not in ('win32', 'win64', 'win8', 'linux', 'mac', 'arm',
                      'android'):
    raise Exception(platform + ' is not an known os type')
  if not target:
    target = 'dbg'
  # Don't enable auto_reboot for people testing locally.
  auto_reboot = ActiveMaster.is_production_host
  if platform == 'win32':
    factory = m_win32[project]
  elif platform == 'win64':
    factory = m_win64[project]
  elif platform == 'win8':
    factory = m_win8[project]
  elif platform == 'linux':
    factory = m_linux[project]
  elif platform == 'mac':
    factory = m_mac[project]
  elif platform == 'arm':
    factory = m_arm[project]
    # Arm board slaves have issue rebooting continuously.
    if 'arm_hw_' in builder_name:
      auto_reboot = False
  elif platform == 'android':
    factory = m_android[project]
  if project in ['nacl', 'nacl-toolchain']:
    builder_factory = factory(
        slave_type=slave_type, tests=tests, options=options,
        factory_properties=factory_properties)
  elif project == 'naclports':
    builder_factory = factory(slave_type=slave_type)
  else:
    assert False
  builddir = builder_name.replace(' ', '-')
  builder = {
    'name': builder_name,
    'builddir': builddir,
    'slavebuilddir': slavebuilddir or builddir,
    'factory': builder_factory,
    'auto_reboot': auto_reboot,
  }
  if slave_names:
    builder['slavenames'] = slave_names
  else:
    builder['slavename'] = builder_name.replace(' ', '-')
  c['builders'].append(builder)


# Try queues.
pools = BuildersPools('nacl')
slaves = slaves_list.SlavesList('slaves.cfg', 'NativeClientTryServer')


def GetSlaveNames(builder_names):
  s = []
  for b in builder_names:
    s += slaves.GetSlavesName(builder=b)
  return s


projects = [
  {
    'name': 'nacl',
    'platforms': [
      {
        'name': 'precise32_newlib_dbg',
        'core_platform': 'linux',
        'builder_names': ['precise32'],
      },
      {
        'name': 'precise32_newlib_opt',
        'core_platform': 'linux',
        'builder_names': ['precise32'],
      },
      {
        'name': 'precise32_glibc_opt',
        'core_platform': 'linux',
        'builder_names': ['precise32'],
      },
      {
        'name': 'precise64_newlib_dbg',
        'core_platform': 'linux',
        'builder_names': ['precise64'],
      },
      {
        'name': 'precise64_newlib_opt',
        'core_platform': 'linux',
        'builder_names': ['precise64'],
      },
      {
        'name': 'precise64_arm_newlib_opt',
        'core_platform': 'linux',
        'builder_names': ['precise64'],
      },
      {
        'name': 'precise64_glibc_opt',
        'core_platform': 'linux',
        'builder_names': ['precise64'],
      },
      {
        'name': 'precise64_validator_opt',
        'core_platform': 'linux',
        'builder_names': ['precise64'],
      },

      {
        'name': 'precise_64-newlib-arm_qemu-pnacl',
        'core_platform': 'linux',
        'builder_names': ['precise64'],
      },
      {
        'name': 'precise_64-newlib-x86_32-pnacl',
        'core_platform': 'linux',
        'builder_names': ['precise64'],
      },
      {
        'name': 'precise_64-newlib-x86_64-pnacl',
        'core_platform': 'linux',
        'builder_names': ['precise64'],
      },
      {
        'name': 'precise_64-newlib-mips-pnacl',
        'core_platform': 'linux',
        'builder_names': ['precise64'],
      },
      {
        'name': 'precise_64-newlib-x86_32-pnacl-spec',
        'core_platform': 'linux',
        'builder_names': ['precise64'],
      },
      {
        'name': 'precise_64-newlib-x86_64-pnacl-spec',
        'core_platform': 'linux',
        'builder_names': ['precise64'],
      },

      {
        'name': 'precise_64-newlib-dbg-asan',
        'core_platform': 'linux',
        'builder_names': ['precise64'],
      },
      {
        'name': 'mac10.7-newlib-dbg-asan',
        'core_platform': 'mac',
        'builder_names': ['mac10.7'],
      },

      {
        'name': 'precise64_newlib_dbg_valgrind',
        'core_platform': 'linux',
        'builder_names': ['precise64'],
      },
      {
        'name': 'precise64_glibc_dbg_valgrind',
        'core_platform': 'linux',
        'builder_names': ['precise64'],
      },
      {
        'name': 'mac10.6_newlib_opt',
        'core_platform': 'mac',
        'builder_names': ['mac10.6'],
      },
      {
        'name': 'mac10.6_glibc_opt',
        'core_platform': 'mac',
        'builder_names': ['mac10.6'],
      },
      {
        'name': 'mac10.6_64_newlib_dbg',
        'core_platform': 'mac',
        'builder_names': ['mac10.6'],
      },
      {
        'name': 'mac10.6_64_glibc_opt',
        'core_platform': 'mac',
        'builder_names': ['mac10.6'],
      },
      {
        'name': 'mac10.7_newlib_opt',
        'core_platform': 'mac',
        'builder_names': ['mac10.7'],
      },
      {
        'name': 'mac10.7_glibc_opt',
        'core_platform': 'mac',
        'builder_names': ['mac10.7'],
      },
      {
        'name': 'mac10.7_64_newlib_dbg',
        'core_platform': 'mac',
        'builder_names': ['mac10.7'],
      },
      {
        'name': 'mac10.7_64_glibc_opt',
        'core_platform': 'mac',
        'builder_names': ['mac10.7'],
      },
      {
        'name': 'mac10.7_arm_newlib_opt',
        'core_platform': 'mac',
        'builder_names': ['mac10.7'],
      },
      {
        'name': 'mac10.8_32_newlib_dbg',
        'core_platform': 'mac',
        'builder_names': ['mac10.8'],
      },
      {
        'name': 'mac10.8_32_glibc_opt',
        'core_platform': 'mac',
        'builder_names': ['mac10.8'],
      },
      {
        'name': 'mac10.8_64_newlib_dbg',
        'core_platform': 'mac',
        'builder_names': ['mac10.8'],
      },
      {
        'name': 'mac10.8_64_glibc_opt',
        'core_platform': 'mac',
        'builder_names': ['mac10.8'],
      },
      {
        'name': 'mac10.8_newlib_opt_pnacl',
        'core_platform': 'mac',
        'builder_names': ['mac10.8'],
      },
      {
        'name': 'win32_newlib_opt',
        'core_platform': 'win32',
        'builder_names': ['win32'],
      },
      {
        'name': 'win32_glibc_opt',
        'core_platform': 'win32',
        'builder_names': ['win32'],
      },
      {
        'name': 'win64_newlib_dbg',
        'core_platform': 'win64',
        'builder_names': ['win64'],
      },
      {
        'name': 'win64_newlib_opt',
        'core_platform': 'win64',
        'builder_names': ['win64'],
      },
      {
        'name': 'win7_64_arm_newlib_opt',
        'core_platform': 'win64',
        'builder_names': ['win64'],
      },
      {
        'name': 'win64_glibc_opt',
        'core_platform': 'win64',
        'builder_names': ['win64'],
      },
      {
        'name': 'win8-64_newlib_dbg',
        'core_platform': 'win8',
        'builder_names': ['win8'],
      },
      {
        'name': 'win8-64_newlib_opt',
        'core_platform': 'win8',
        'builder_names': ['win8'],
      },
      {
        'name': 'win7_64_newlib_opt_pnacl',
        'core_platform': 'win64',
        'builder_names': ['win64'],
      },
      {
        'name': 'mac10.6-newlib-dbg-clang',
        'core_platform': 'mac',
        'builder_names': ['mac10.6'],
      },
      {
        'name': 'precise_64-newlib-dbg-clang',
        'core_platform': 'linux',
        'builder_names': ['precise64'],
      },
      {
        'name': 'arm_opt_panda',
        'core_platform': 'arm',
        'builder_names': ['precise64'],
        # Needed for triggering to happen (for now).
        'tests': ['nacl_trigger_arm_hw_opt_panda'],
      },
      {
        'name': 'arm_perf_panda',
        'core_platform': 'arm',
        'builder_names': ['precise64'],
        # Needed for triggering to happen (for now).
        'tests': ['nacl_trigger_arm_hw_perf_panda'],
      },
      {
        'name': 'arm_hw_opt_panda',
        'core_platform': 'arm',
        'builder_names': ['panda'],
        'factory_properties': {'update_scripts_gclient_jobs': 1},
      },
      {
        'name': 'arm_hw_perf_panda',
        'core_platform': 'arm',
        'builder_names': ['panda'],
        'factory_properties': {'update_scripts_gclient_jobs': 1},
      },
      # Android.
      {
        'name': 'precise64-newlib-dbg-android',
        'core_platform': 'linux',
        'builder_names': ['precise64'],
      },
      {
        'name': 'precise64-newlib-opt-android',
        'core_platform': 'linux',
        'builder_names': ['precise64'],
      },
      # Special bare metal.
      {
        'name': 'xp-bare-shared',
        'core_platform': 'win32',
        'builder_names': ['bare_xp'],
      },
      {
        'name': 'win7-bare-shared',
        'core_platform': 'win64',
        'builder_names': ['bare_win7'],
      },
      {
        'name': 'precise64-bare-shared',
        'core_platform': 'linux',
        'builder_names': ['bare_precise64'],
      },
      {
        'name': 'mac-bare-shared',
        'core_platform': 'mac',
        'builder_names': ['bare_mac'],
      },
    ],
  },
  {
    'name': 'nacl-toolchain',
    'platforms': [
      {
        'name': 'precise64-newlib',
        'core_platform': 'linux',
        'builder_names': ['precise64'],
      },
      {
        'name': 'mac-newlib',
        'core_platform': 'mac',
        'builder_names': ['mac10.6'],
      },
      {
        'name': 'win7-newlib',
        'core_platform': 'win64',
        'builder_names': ['win64'],
      },

      {
        'name': 'precise64-newlib-arm',
        'core_platform': 'linux',
        'builder_names': ['precise64'],
      },
      {
        'name': 'mac-newlib-arm',
        'core_platform': 'mac',
        'builder_names': ['mac10.6'],
      },

      {
        'name': 'precise64-glibc',
        'core_platform': 'linux',
        'builder_names': ['precise64'],
      },
      {
        'name': 'mac-glibc',
        'core_platform': 'mac',
        'builder_names': ['mac10.6'],
      },
      {
        'name': 'win7-glibc',
        'core_platform': 'win64',
        'builder_names': ['win64'],
      },

      {
        'name': 'mac-pnacl-x86_32',
        'core_platform': 'mac',
        'builder_names': ['mac10.6'],
      },
      {
        'name': 'linux-pnacl-x86_32',
        'core_platform': 'linux',
        'builder_names': ['precise32'],
      },
      {
        'name': 'linux-pnacl-x86_64',
        'core_platform': 'linux',
        'builder_names': ['precise64'],
      },
      {
        'name': 'win7-pnacl-x86_64',
        'core_platform': 'win64',
        'builder_names': ['win64'],
      },
      {
        'name': 'precise64-bionic',
        'core_platform': 'linux',
        'builder_names': ['precise64'],
      },

      {
        'name': 'trusty64-toolchain_cross',
        'core_platform': 'linux',
        'builder_names': ['trusty64'],
      },

      {
        'name': 'asan',
        'core_platform': 'linux',
        'builder_names': ['sanitizer'],
        'slavebuilddir': 'nacl-asan',
      },
      {
        'name': 'msan',
        'core_platform': 'linux',
        'builder_names': ['sanitizer'],
        'slavebuilddir': 'nacl-msan',
      },
      {
        'name': 'tsan',
        'core_platform': 'linux',
        'builder_names': ['sanitizer'],
        'slavebuilddir': 'nacl-tsan',
      },
      {
        'name': 'ubsan',
        'core_platform': 'linux',
        'builder_names': ['sanitizer'],
        'slavebuilddir': 'nacl-ubsan',
      },
    ],
  },
]

# Add in naclports programatically as it is very regular.
naclports_platforms = []
for platform, builder_names in [
    ['linux', ['precise64']],
    ['mac', ['mac10.6', 'mac10.7', 'mac10.8']]]:
  for toolchain in ['glibc', 'newlib', 'bionic', 'pnacl', 'clang', 'emscripten']:
    for shard in xrange(0, 5):
      naclports_platforms.append(
        {
          'name': '%s-%s-%d' % (platform, toolchain, shard),
          'core_platform': platform,
          'builder_names': builder_names,
        },
      )
projects.append(
  {
    'name': 'naclports',
    'platforms': naclports_platforms,
  },
)

for project in projects:
  for platform in project['platforms']:
    true_builder_names = platform.get('builder_names', [platform['name']])
    slave_names = GetSlaveNames(true_builder_names)
    # This allows builders to pluck out particular slaves to use.
    # It is used for the arm cross-compile builds to prevent race conditions
    # by allowing only a single slave to write to a share archive URL.
    slave_names = platform.get('raw_slave_names', slave_names)
    name = project['name'] + '-' + platform['name']
    factory_properties=platform.get(
       'factory_properties', project.get('factory_properties', {}))
    factory_properties.update({'gclient_timeout': 1800})

    CreateBot(platform=platform.get('core_platform', platform['name']),
              target=platform.get('target', project.get('target')),
              tests=platform.get('tests', project.get('tests')),
              mode=platform.get('mode'),
              slave_type=platform.get('slave_type', 'Trybot'),
              options=platform.get('options', project.get('options')),
              factory_properties=factory_properties,
              slave_names=slave_names,
              project=project['name'],
              slavebuilddir=platform.get(
                  'slavebuilddir',
                  project.get('slavebuilddir', project['name'])),
              builder_name=name)
    pools[project['name']].append(name)


m_annotator = annotator_factory.AnnotatorFactory(ActiveMaster)

b_nacl_presubmit = {
  'name': 'nacl-presubmit',
  'slavebuilddir': 'nacl',
  'factory':
      m_annotator.BaseFactory('run_presubmit', {'repo_name': 'nacl'}),
  'slavenames': GetSlaveNames(['precise64'])
}
c['builders'].append(b_nacl_presubmit)

b_naclports_presubmit = {
  'name': 'naclports-presubmit',
  'slavebuilddir': 'naclports',
  'factory':
      m_annotator.BaseFactory('run_presubmit', {'repo_name': 'naclports'}),
  'slavenames': GetSlaveNames(['precise64'])
}
c['builders'].append(b_naclports_presubmit)

b_gyp_presubmit = {
  'name': 'gyp-presubmit',
  'slavebuilddir': 'gyp',
  'factory':
      m_annotator.BaseFactory('run_presubmit', {'repo_name': 'gyp'}),
  'slavenames': GetSlaveNames(['precise64'])
}
c['builders'].append(b_gyp_presubmit)

# Set "root" build property to "native_client" in all builders
for b in c['builders']:
  b.setdefault('properties', {})['root'] = 'native_client'

####### BUILDSLAVES

# The 'slaves' list defines the set of allowable buildslaves. List all the
# slaves registered to a builder. Remove dupes.
c['slaves'] = master_utils.AutoSetupSlaves(c['builders'],
                                           config.Master.GetBotPassword())


####### SCHEDULERS

# Configure the Schedulers;
# Main Tryscheduler for the try queue. groups is defined in the loop above.
c['schedulers'] = []

code_review_sites = {
  'nacl': ActiveMaster.code_review_site,
  'nacl-toolchain': ActiveMaster.code_review_site,
  'gyp': ActiveMaster.code_review_site,
  'naclports': ActiveMaster.code_review_site,
}
c['schedulers'].append(TryJobHTTP(
    name='try_job_http',
    port=ActiveMaster.try_job_port,
    code_review_sites=code_review_sites,
    pools=pools))

if ActiveMaster.svn_url:
  c['schedulers'].append(TryJobSubversion(
      name='try_job_svn',
      svn_url=ActiveMaster.svn_url,
      code_review_sites=code_review_sites,
      pools=pools))

if LISTEN_TO_RIETVELD:
  c['schedulers'].append(TryJobRietveld(
        name='try_job_rietveld_nacl',
        pools=pools,
        code_review_sites=code_review_sites,
        project='nacl',
        filter_master=True))
  c['schedulers'].append(TryJobRietveld(
        name='try_job_rietveld_gyp',
        pools=pools,
        code_review_sites=code_review_sites,
        project='gyp',
        filter_master=True))
  c['schedulers'].append(TryJobRietveld(
        name='try_job_rietveld_naclports',
        pools=pools,
        code_review_sites=code_review_sites,
        project='naclports',
        filter_master=True))

for mode in ['opt_panda', 'perf_panda']:
  s = Triggerable(
      name='arm_%s_hw_tests' % mode,
      builderNames=['nacl-arm_hw_%s' % mode])
  c['schedulers'].append(s)


####### STATUS TARGETS

# Buildbot master url:
# Must come before AutoSetupMaster().
c['buildbotURL'] = ActiveMaster.buildbot_url

# Adds common status and tools to this master.
master_utils.AutoSetupMaster(c, ActiveMaster, False,
                             public_html='../master.chromium/public_html',
                             templates=['../master.client.nacl/templates'])

# Add more.

if MAIL_NOTIFIER:
  # Add a dumb MailNotifier first so it will be used for BuildSlave with
  # notify_on_missing set when they go missing.
  from buildbot.status import mail
  c['status'].append(mail.MailNotifier(
      fromaddr=ActiveMaster.from_address,
      builders=[],
      relayhost=config.Master.smtp,
      lookup=master_utils.UsersAreEmails()))

  # Try job result emails.
  from master.try_mail_notifier import TryMailNotifier
  c['status'].append(TryMailNotifier(
      fromaddr=ActiveMaster.from_address,
      reply_to=ActiveMaster.reply_to,
      subject="try of %(reason)s @ r%(revision)s %(timestamp)s",
      mode='all',
      relayhost=config.Master.smtp,
      lookup=master_utils.UsersAreEmails()))

if UPDATE_CODEREVIEW:
  from master.status_push import TryServerHttpStatusPush
  c['status'].append(
      TryServerHttpStatusPush(serverUrl=ActiveMaster.code_review_site))


# Keep last try jobs, the default is too low. Must keep at least a few days
# worth of try jobs.
c['buildHorizon'] = 2000
c['logHorizon'] = 2000
# Must be at least 2x the number of slaves.
c['eventHorizon'] = 100
# Must be at least 2x the number of on-going builds.
c['buildCacheSize'] = 100


####### PROJECT IDENTITY

# The 'projectURL' string will be used to provide a link
# from buildbot HTML pages to your project's home page.
c['projectURL'] = 'http://go/ChromeTryServer'
